#include "laurin-network-device.h"
#include <string.h>  //for memset, memcpy
#include <pcap.h>


LaurinNetworkDevice::LaurinNetworkDevice(const Glib::ustring& ifaceName): LaurinDevice(ifaceName), LaurinCaptureInterface(ifaceName)
{
	_injectionContext = NULL;
	_network = NULL;
	_mac = NULL;
	_ip = -1;

	_ready = false;
	if(setDeviceUp())
	{

		openCaptureContext();
		if(_ready = openInjectionContext() && isCaptureContextOpen())
		{

			u_int32_t mask;
			u_int32_t net;
			char errbuf[PCAP_ERRBUF_SIZE];
			memset(errbuf, 0, PCAP_ERRBUF_SIZE);

			if(pcap_lookupnet(ifaceName.c_str(), &net, & mask, errbuf) < 0)
				_ready = false;

			else
				_network = new LaurinIPNetwork(net, mask);
		}
	}
}


LaurinNetworkDevice::~LaurinNetworkDevice()
{
	closeInjectionContext();

	if(_mac != NULL)
		free(_mac);

	if(_network)
		delete _network;
}


bool LaurinNetworkDevice::openInjectionContext()
{
	char errbuf[LIBNET_ERRBUF_SIZE];

	if((_injectionContext = libnet_init(LIBNET_LINK_ADV, (char*) _ifaceName.c_str(), errbuf)) == NULL)
		return false;

	struct libnet_ether_addr *mac;


	if((mac = libnet_get_hwaddr(_injectionContext)) == NULL)
		return false;

	_mac = (u_int8_t*) mac->ether_addr_octet;

	_ip = libnet_get_ipaddr4(_injectionContext);

	return true;
}


void LaurinNetworkDevice::closeInjectionContext()
{
	if(_injectionContext != NULL)
			libnet_destroy(_injectionContext);
}


u_int32_t LaurinNetworkDevice::getIP() const
{
	return _ip;
}


u_int8_t* LaurinNetworkDevice::getMAC() const
{
	return _mac;
}


libnet_t* LaurinNetworkDevice::getInjectionContext() const
{
	return _injectionContext;
}


bool LaurinNetworkDevice::isInitialized() const
{
	return _ready && isCaptureContextOpen();
}


LaurinIPNetwork* LaurinNetworkDevice::getNetwork() const
{
	return _network;
}


bool LaurinNetworkDevice::setCaptureOptions()
{
	return LaurinCaptureInterface::setCaptureOptions() && (pcap_set_promisc(getCaptureContext(), 0) >= 0);
}
